package com.summer.filesync.config;

import com.summer.filesync.util.Logger;
import com.summer.filesync.util.StringUtils;
import java.io.*;
import java.util.Properties;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/** 配置管理器 管理系统配置参数 */
public class ConfigManager {

  private static final Logger logger = Logger.getLogger(ConfigManager.class);
  private static final String DEFAULT_CONFIG_FILE = "config/system.properties";

  private static ConfigManager instance;
  private static final Object INSTANCE_LOCK = new Object();

  private Properties properties;
  private String configFilePath;
  private final ReadWriteLock lock = new ReentrantReadWriteLock();

  private ConfigManager() {
    this.configFilePath = DEFAULT_CONFIG_FILE;
    this.properties = new Properties();
    loadDefaultConfig();
  }

  /** 获取单例实例 */
  public static ConfigManager getInstance() {
    if (instance == null) {
      synchronized (INSTANCE_LOCK) {
        if (instance == null) {
          instance = new ConfigManager();
        }
      }
    }
    return instance;
  }

  /** 加载默认配置 */
  private void loadDefaultConfig() {
    // 网络配置
    properties.setProperty(SystemConfig.NETWORK_PORT, "8888");
    properties.setProperty(SystemConfig.NETWORK_TIMEOUT, "30000");
    properties.setProperty(SystemConfig.MAX_CONNECTIONS, "10");
    properties.setProperty(SystemConfig.HEARTBEAT_INTERVAL, "30000");

    // 同步配置
    properties.setProperty(SystemConfig.SYNC_INTERVAL, "60000");
    properties.setProperty(SystemConfig.CONFLICT_STRATEGY, "TIMESTAMP_PRIORITY");
    properties.setProperty(SystemConfig.WATCH_DIRECTORIES, "sync");
    properties.setProperty(SystemConfig.AUTO_SYNC_ENABLED, "true");

    // 数据库配置
    properties.setProperty(SystemConfig.DB_PATH, "database/sync_system.db");
    properties.setProperty(SystemConfig.DB_POOL_SIZE, "5");

    // 文件传输配置
    properties.setProperty(SystemConfig.TRANSFER_CHUNK_SIZE, "8192");
    properties.setProperty(SystemConfig.TRANSFER_TIMEOUT, "120000");
    properties.setProperty(SystemConfig.MAX_FILE_SIZE, "104857600"); // 100MB

    // 日志配置
    properties.setProperty(SystemConfig.LOG_LEVEL, "INFO");
    properties.setProperty(SystemConfig.LOG_FILE_PATH, "logs/system.log");
    properties.setProperty(SystemConfig.LOG_FILE_ENABLED, "true");

    // 节点配置
    properties.setProperty(SystemConfig.NODE_NAME, "SyncNode");
    properties.setProperty(SystemConfig.NODE_ID, StringUtils.generateShortUUID());
  }

  /** 设置配置文件路径 */
  public void setConfigFilePath(String filePath) {
    lock.writeLock().lock();
    try {
      this.configFilePath = filePath;
    } finally {
      lock.writeLock().unlock();
    }
  }

  /** 加载配置文件 */
  public void loadConfig() throws IOException {
    lock.writeLock().lock();
    try {
      File configFile = new File(configFilePath);
      if (!configFile.exists()) {
        logger.info("Config file not found, creating default: " + configFilePath);
        saveConfig();
        return;
      }

      try (FileInputStream fis = new FileInputStream(configFile)) {
        properties.load(fis);
        logger.info("Loaded configuration from: " + configFilePath);
      }
    } finally {
      lock.writeLock().unlock();
    }
  }

  /** 保存配置 */
  public void saveConfig() throws IOException {
    lock.readLock().lock();
    try {
      File configFile = new File(configFilePath);
      File parentDir = configFile.getParentFile();

      if (parentDir != null && !parentDir.exists()) {
        if (!parentDir.mkdirs()) {
          throw new IOException("Failed to create config directory: " + parentDir.getPath());
        }
      }

      try (FileOutputStream fos = new FileOutputStream(configFile)) {
        properties.store(fos, "Distributed File Sync System Configuration");
        logger.info("Saved configuration to: " + configFilePath);
      }
    } finally {
      lock.readLock().unlock();
    }
  }

  /** 获取字符串配置值 */
  public String getProperty(String key, String defaultValue) {
    lock.readLock().lock();
    try {
      return properties.getProperty(key, defaultValue);
    } finally {
      lock.readLock().unlock();
    }
  }

  /** 获取整数配置值 */
  public int getIntProperty(String key, int defaultValue) {
    String value = getProperty(key, String.valueOf(defaultValue));
    try {
      return Integer.parseInt(value);
    } catch (NumberFormatException e) {
      logger.warn(
          "Invalid integer value for key "
              + key
              + ": "
              + value
              + ", using default: "
              + defaultValue);
      return defaultValue;
    }
  }

  /** 获取长整数配置值 */
  public long getLongProperty(String key, long defaultValue) {
    String value = getProperty(key, String.valueOf(defaultValue));
    try {
      return Long.parseLong(value);
    } catch (NumberFormatException e) {
      logger.warn(
          "Invalid long value for key " + key + ": " + value + ", using default: " + defaultValue);
      return defaultValue;
    }
  }

  /** 获取布尔配置值 */
  public boolean getBooleanProperty(String key, boolean defaultValue) {
    String value = getProperty(key, String.valueOf(defaultValue));
    return Boolean.parseBoolean(value);
  }

  /** 设置配置值 */
  public void setProperty(String key, String value) {
    lock.writeLock().lock();
    try {
      properties.setProperty(key, value);
    } finally {
      lock.writeLock().unlock();
    }
  }

  /** 设置整数配置值 */
  public void setIntProperty(String key, int value) {
    setProperty(key, String.valueOf(value));
  }

  /** 设置长整数配置值 */
  public void setLongProperty(String key, long value) {
    setProperty(key, String.valueOf(value));
  }

  /** 设置布尔配置值 */
  public void setBooleanProperty(String key, boolean value) {
    setProperty(key, String.valueOf(value));
  }

  /** 移除配置项 */
  public void removeProperty(String key) {
    lock.writeLock().lock();
    try {
      properties.remove(key);
    } finally {
      lock.writeLock().unlock();
    }
  }

  /** 检查配置项是否存在 */
  public boolean containsKey(String key) {
    lock.readLock().lock();
    try {
      return properties.containsKey(key);
    } finally {
      lock.readLock().unlock();
    }
  }

  /** 重新加载配置 */
  public void reloadConfig() throws IOException {
    logger.info("Reloading configuration...");
    loadConfig();
  }
}
